using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using JoyfulHomeJourney.BackEnd.Infrastructure.Atrributes;
using JoyfulHomeJourney.BackEnd.Infrastructure.Dtos.Requests.Objects;
using JoyfulHomeJourney.BackEnd.Infrastructure.Dtos.Responses;
using JoyfulHomeJourney.BackEnd.Infrastructure.Dtos.Responses.Objects;
using JoyfulHomeJourney.BackEnd.Infrastructure.EFCore;
using JoyfulHomeJourney.BackEnd.Infrastructure.Tools;
using JoyfulHomeJourney.BackEnd.Server.EFCore;
using JoyfulHomeJourney.BackEnd.Server.Instances.Extends.Requests;
using JoyfulHomeJourney.BackEnd.Server.Instances.Extends.Responses;
using JoyfulHomeJourney.BackEnd.Server.Interfaces;
using Microsoft.EntityFrameworkCore;
namespace JoyfulHomeJourney.BackEnd.Server.Instances
{
    /// <summary>
    /// 一个类包含了服务类所需的所有仓库表的实例，仅提供给该服务类使用，请将所有服务类所需的仓库表的实例都放在该类中。
    /// 仓库表的实例指提供了操作数据库指定表的所有方法的对象
    /// </summary>
    internal class SysCarServicesEF
    {
        public SysCarServicesEF(DbContext dbContext)
        {
            sysCarServicesServerEF = new SysCarServicesServerEF(dbContext);
            sysProductsServerEF = new SysProductsServerEF(dbContext);
            dictionarysServerEF = new DictionarysServerEF(dbContext);
        }
        public SysCarServicesServerEF sysCarServicesServerEF { get; set; }
        public SysProductsServerEF sysProductsServerEF { get; set; }
        public DictionarysServerEF dictionarysServerEF { get; set; }
    }
    [InjectClass]
    public class SysCarServicesServer : ISysCarServicesServer
    {
        private readonly SysCarServicesEF _sysCarServicesEF;//包含所有所需仓库表实现的对象
                                                            // 请不要修改该构造方法,也无需添加属性，而应该在上面的EF类中添加属性和构造函数赋值语句
        public SysCarServicesServer(DbContext dbContext)
        {
            _sysCarServicesEF = new SysCarServicesEF(dbContext);
        }
        private string AddValidator(RequestSysCarServicesDto dto)
        {
            if (dto.imageFileList.Count > 10)
            {
                return "最多只能上传十张图片";
            }
            if (dto.deduction > dto.price * dto.discount / 100)
            {
                return "抵扣金额不能大于等于价格折扣后的金额";
            }
            return null;
        }
        public async Task<ResponseApiDto> AddAsync(RequestSysCarServicesDto dto)
        {
            string validatedResult = AddValidator(dto);
            if (validatedResult != null)
            {
                ResponseApiDto.Fail(validatedResult);
            }
            int affectedRows = 0;
            List<string> newImagePaths = new List<string>();
            await _sysCarServicesEF.sysCarServicesServerEF.ExecuteInTransactionAsync(async () =>
            {
                // 添加图片
                string id = Tools.Guid_2();
                string willInsertImages = "";
                // 上传图片
                foreach (var image in dto.imageFileList)
                {
                    string temp = await Tools.UploadImage(image, Path.Combine(Tools.GetImageCarServicePath(), id));
                    willInsertImages += temp + ",";
                    newImagePaths.Add(Path.Combine(Tools.GetImageCarServicePath(), id, temp));
                }
                // 添加产品
                var product = dto.ToSysProductsCreateEntity();
                product.PImages = willInsertImages.Substring(0, willInsertImages.Length - 1);
                product.PCategory = "car_services";
                affectedRows += await _sysCarServicesEF.sysProductsServerEF.AddAsync(product);
                // 添加服务
                var carService = dto.ToCreateEntity();
                carService.CsProductId = product.PId;
                affectedRows += await _sysCarServicesEF.sysCarServicesServerEF.AddAsync(carService, id);
            }, () =>
            {
                affectedRows = 0;
                // 删除图片
                foreach (var imagePath in newImagePaths)
                {
                    Tools.DeleteImage(imagePath);
                }
                // 删除文件夹
                Tools.DeleteDirectory(Path.GetDirectoryName(newImagePaths[0]));
                return null;
            });
            return ResponseApiDto.Create(affectedRows);
        }
        // 不带文件的添加
        public async Task<ResponseApiDto> AddAsync2(RequestSysCarServicesDto dto)
        {
            int affectedRows = 0;
            string id = Tools.Guid_1();
            await _sysCarServicesEF.sysCarServicesServerEF.ExecuteInTransactionAsync(async () =>
            {
                // 添加产品表
                var product = dto.ToSysProductsCreateEntity();
                product.PCategory = "sys_car_supplies";
                product.PImages = "";
                affectedRows += await _sysCarServicesEF.sysProductsServerEF.AddAsync(product,id);
                // 添加汽车服务表
                var carService = dto.ToCreateEntity();
                carService.CsProductId = product.PId;
                affectedRows += await _sysCarServicesEF.sysCarServicesServerEF.AddAsync(carService);
            }, () => { affectedRows = 0; return null; });
            return ResponseApiDto.Create(affectedRows, data: affectedRows > 0 ? id : null);
        }
        private async Task<bool> Exist(string id)
        {
            return await _sysCarServicesEF.sysCarServicesServerEF.Query(d => d.CsId == id).AnyAsync();
        }
        public async Task<ResponseApiDto> DeleteAsync(RequestSysCarServicesDto dto)
        {
            if (!await Exist(dto.id))
            {
                return ResponseApiDto.Fail("该汽车服务不存在");
            }
            int affectedRows = 0;
            List<FileInfo> deletedImages = new List<FileInfo>();// 删除的图片文件
            await _sysCarServicesEF.sysCarServicesServerEF.ExecuteInTransactionAsync(async () =>
            {
                string productId = await _sysCarServicesEF.sysCarServicesServerEF.Query(d => d.CsId == dto.id).Select(d => d.CsProductId).SingleOrDefaultAsync();
                // 从数据库查询图片名称，并删除
                var oldImageNames = await _sysCarServicesEF.sysProductsServerEF.Query(d => d.PId == productId).Select(d => d.PImages).SingleAsync();
                foreach (var image in oldImageNames.Split(','))
                {
                    FileInfo file = new FileInfo(Path.Combine(Tools.GetImageCarServicePath(), dto.id, image));
                    deletedImages.Add(file);
                    Tools.DeleteImage(Path.Combine(Tools.GetImageCarServicePath(), dto.id, image));
                }
                // 删除服务
                affectedRows += await _sysCarServicesEF.sysCarServicesServerEF.DeleteAsync(new SysCarServices { CsId = dto.id });
                // 删除产品
                affectedRows += await _sysCarServicesEF.sysProductsServerEF.DeleteAsync(new SysProducts { PId = productId });
            }, () =>
            {
                affectedRows = 0;
                // 恢复图片
                foreach (var deletedImage in deletedImages)
                {
                    deletedImage.CopyTo(Path.Combine(Tools.GetImageCarServicePath(), dto.id, deletedImage.Name), overwrite: true);
                }
                return null;
            });
            return ResponseApiDto.Create(affectedRows);
        }
        public async Task<ResponseApiDto> UpdateAsync(RequestSysCarServicesDto dto)
        {
            if (!await Exist(dto.id))
            {
                return ResponseApiDto.Fail("该汽车服务不存在");
            }
            if (dto.imageOrders.Count > 10)
            {
                return ResponseApiDto.Fail("最多只能上传十张图片");
            }
            var affectedRows = 0;
            List<string> createdImagePaths = new List<string>();// 新增的图片的位置
            List<FileInfo> deletedImages = new List<FileInfo>();// 删除的图片文件
            await _sysCarServicesEF.sysCarServicesServerEF.ExecuteInTransactionAsync(async () =>
            {
                string newImageNames = "";// 新的图片名集合字符串
                List<string> imagesNames = dto.imageFileList?.Select(d => d.FileName).ToList() ?? new List<string>();// 要新增的图片名称列表
                // 新增图片
                foreach (var item in dto.imageOrders)
                {
                    if (imagesNames.Contains(item))
                    {
                        var image = dto.imageFileList.Where(d => d.FileName == item).SingleOrDefault();
                        string newImageName = await Tools.UploadImage(image, Path.Combine(Tools.GetImageCarServicePath(), dto.id));
                        newImageNames += newImageName + ",";
                        createdImagePaths.Add(Path.Combine(Tools.GetImageCarServicePath(), dto.id, newImageName));
                    }
                    else if (dto.retainImages?.Contains(item) ?? false)
                    {
                        newImageNames += item + ",";
                    }
                }
                // 比对数据库的数据并删除不保留的图片
                var productId = await _sysCarServicesEF.sysCarServicesServerEF.Query(d => d.CsId == dto.id).Select(d => d.CsProductId).SingleAsync();
                var oldImageNames = await _sysCarServicesEF.sysProductsServerEF.Query(d => d.PId == productId).Select(d => d.PImages).SingleAsync();
                foreach (var oldImageName in oldImageNames.Split(",").ToList())
                {
                    if (!(dto.retainImages?.Contains(oldImageName) ?? false))
                    {
                        FileInfo file = new FileInfo(Path.Combine(Tools.GetImageCarServicePath(), dto.id, oldImageName));
                        deletedImages.Add(file);
                        Tools.DeleteImage(Path.Combine(Tools.GetImageCarServicePath(), dto.id, oldImageName));
                    }
                }
                // 修改汽车表
                var carService = dto.ToCreateEntity();
                affectedRows += await _sysCarServicesEF.sysCarServicesServerEF.UpdateAllProperNotNullAsync(carService);
                // 修改产品表
                var product = dto.ToSysProductsCreateEntity();
                product.PId = productId;
                product.PImages = newImageNames.Substring(0, newImageNames.Length - 1);
                affectedRows += await _sysCarServicesEF.sysProductsServerEF.UpdateAllProperNotNullAsync(product);
            }, () =>
            {
                affectedRows = 0;
                // 删除图片
                foreach (var imagePath in createdImagePaths)
                {
                    Tools.DeleteImage(imagePath);
                }
                // 恢复图片
                foreach (var deletedImage in deletedImages)
                {
                    deletedImage.CopyTo(Path.Combine(Tools.GetImageCarServicePath(), dto.id, deletedImage.Name), overwrite: true);
                }
                return null;
            });
            return ResponseApiDto.Create(affectedRows);
        }

        public async Task<ResponseApiDto> Detail(string id)
        {
            if (!await Exist(id))
            {
                return ResponseApiDto.Fail("该汽车服务不存在");
            }
            SysCarServices service = await _sysCarServicesEF.sysCarServicesServerEF.Query(d => d.CsId == id).SingleAsync();
            SysProducts product = await _sysCarServicesEF.sysProductsServerEF.Query(d => d.PId == service.CsProductId).SingleOrDefaultAsync();
            ResponseSysCarServicesDto responseDto = service.ToResponseDto(product);
            responseDto.serviceTypeName = await _sysCarServicesEF.dictionarysServerEF.Query(d => d.DId == responseDto.serviceType).Select(d => d.DValue).SingleOrDefaultAsync();
            return ResponseApiDto.Success("数据已获取", responseDto);
        }
        public async Task<ResponseApiDto> PaginationAsync(int page, int limit, string key, string shopId, string field, bool? order)
        {
            int total = 0;
            List<ResponseSysCarServicesDto> data = new List<ResponseSysCarServicesDto>();
            var iq = orderByField(_sysCarServicesEF.sysCarServicesServerEF.Query(d => key == null || d.CsProduct.PName.Contains(key)), field, order ?? true);
            total = await iq.CountAsync();
            List<SysCarServices> sysCarServicess = await iq.Skip((page - 1) * limit).Take(limit).ToListAsync();
            foreach (var sysCarServices in sysCarServicess)
            {
                var product = await _sysCarServicesEF.sysProductsServerEF.Query(d => d.PId == sysCarServices.CsProductId).SingleOrDefaultAsync();
                var responseDto = sysCarServices.ToResponseDto(product);
                responseDto.serviceTypeName = await _sysCarServicesEF.dictionarysServerEF.Query(d => d.DId == responseDto.serviceType).Select(d => d.DValue).SingleOrDefaultAsync();
                data.Add(responseDto);
            }
            return ResponseApiDto.Success("数据已获取", new ResponsePaginationDto { total = total, data = data });
        }
        
        private IQueryable<SysCarServices> orderByField(IQueryable<SysCarServices> iq, string field, bool isAsc)
        {
            switch (field)
            {
                case "name":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PName);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PName);
                    }
                    break;
                case "serviceTypeName":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsServiceTypeNavigation.DValue);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsServiceTypeNavigation.DValue);
                    }
                    break;
                case "serviceArea":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsServiceArea);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsServiceArea);
                    }
                    break;
                case "price":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PPrice);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PPrice);
                    }
                    break;
                case "duration":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsDuration);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsDuration);
                    }
                    break;
                case "appointmentRequired":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsAppointmentRequired);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsAppointmentRequired);
                    }
                    break;
                case "createAtStr":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PCreateAt);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PCreateAt);
                    }
                    break;
                case "updateAtStr":
                    if (isAsc)
                    {
                        iq = iq.OrderBy(d => d.CsProduct.PUpdateAt);
                    }
                    else
                    {
                        iq = iq.OrderByDescending(d => d.CsProduct.PUpdateAt);
                    }
                    break;
                default:
                    iq = iq.OrderByDescending(d => d.CsProduct.PCreateAt);
                    break;
            }
            return iq;
        }
    }
}
